import React, { useRef, useState, useEffect } from 'react';
import * as THREE from 'three';
import { UserAuth } from '../../utils/hooks';
import IndexDBWrapper from 'indexdbwrapper';
import NotAuth from '../../components/NotAuth';
import * as moment from 'moment';
import {
  InputNumber,
  Row,
  Col,
  Layout,
  Menu,
  Dropdown,
  Space,
  Segmented,
  Upload,
  Button,
  Tree,
  Tabs,
  Descriptions,
  Modal,
  Input,
  message,
  Spin,
} from 'antd';
import { saveAs } from 'file-saver';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
//import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment';
import { CodeSandboxOutlined, PlaySquareOutlined, CopyOutlined } from '@ant-design/icons';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import { createText } from 'three/examples/jsm/webxr/Text2D.js';
import { Loader } from './Loader';
import translate from './translate.svg';
import scale from './scale.svg';
import rotate from './rotate.svg';
import bump from './hardwood2_bump.jpg';
import diffuse from './hardwood2_diffuse.jpg';
import roughness from './hardwood2_roughness.jpg';

import MonacoEditor from 'react-monaco-editor';
import { Scene } from 'three';
const { Content } = Layout;
const { TabPane } = Tabs;
let objectPositionOnDown = null;
let objectRotationOnDown = null;
let objectScaleOnDown = null;
const dbName = 'scene',
  storeName = 'model',
  version = 1;

const db = new IndexDBWrapper(dbName, version, {
  onupgradeneeded(event) {
    const db = event.target.result; // 数据库对象
    let objectStore;
    if (!db.objectStoreNames.contains(storeName)) {
      objectStore = db.createObjectStore(storeName, { keyPath: 'id' }); // 创建表
      // objectStore.createIndex('createTime', 'createTime', { unique: false }) // 创建索引 可以让你搜索任意字段
    }
  },
});

const camera = new THREE.PerspectiveCamera(45, 1381 / 725, 0.01, 10000);
camera.position.z = 50;
const stats = new Stats();

let sceneHelper = new THREE.Scene();
// const helper = new THREE.GridHelper(100, 25, 0x888888, 0x444444);
// helper.tag = 'helper';
// sceneHelper.add(helper);
const geometry = new THREE.BoxGeometry(10, 10, 10);
const material = new THREE.MeshPhongMaterial({ color: 0x4080ff, dithering: true });

const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.tag = 'obj';

let scene = new THREE.Scene();
scene.add(mesh);

const box = new THREE.Box3();

const selectionBox = new THREE.Box3Helper(box);
selectionBox.material.depthTest = false;
selectionBox.material.transparent = true;
selectionBox.visible = false;
sceneHelper.add(selectionBox);

let mixer = new THREE.AnimationMixer(scene);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.shadowMap.enabled = true;

let floorMat = new THREE.MeshStandardMaterial({
  roughness: 0.8,
  color: 0xffffff,
  metalness: 0.2,
  bumpScale: 0.0005,
});
const textureLoader = new THREE.TextureLoader();
textureLoader.load(diffuse, function (map) {
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  map.anisotropy = 4;
  map.repeat.set(10, 24);
  map.encoding = THREE.sRGBEncoding;
  floorMat.map = map;
  floorMat.needsUpdate = true;
  console.log(1);
});
textureLoader.load(bump, function (map) {
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  map.anisotropy = 4;
  map.repeat.set(10, 24);
  floorMat.bumpMap = map;
  floorMat.needsUpdate = true;
  console.log(2);
});
textureLoader.load(roughness, function (map) {
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  map.anisotropy = 4;
  map.repeat.set(10, 24);
  floorMat.roughnessMap = map;
  floorMat.needsUpdate = true;
  console.log(3);
});

//摄像头
let controls = new OrbitControls(camera, renderer.domElement);
controls.tag = 'helper';
controls.target.set(0, 0, 0);
controls.update();
controls.enablePan = false;
controls.enableDamping = true;

//物体控制
let control = new TransformControls(camera, renderer.domElement);
control.setMode('translate');

// control.attach(mesh);
sceneHelper.add(control);

control.addEventListener('change', function () {
  const object = control.object;

  if (object !== undefined) {
    box.setFromObject(object, true);
    selectionBox.visible = true;
  } else {
    selectionBox.visible = false;
  }
});

const clock = new THREE.Clock();

let clickSelect = false;
let scripts = {};
let curIndex;
let monacoEditor;
let outPlay = false;
let events = {
  start: [],
  update: [],
  click: {},
};
let editHis = [];
let mulUpload = false;
let cloneScene = new THREE.Scene();
let position1, position2;
const sceneLoader = new THREE.ObjectLoader();
//该变量解决循环引用bug
let lightHelperOut = null;
let flag = 0;
const backHis = e => {
  if (outPlay) return;
  if (e.key == 'z' && e.ctrlKey) {
    if (editHis.length == 0) {
      message.warn('无可撤回记录');
    } else {
      let temp = editHis.pop();

      let tar = scene.getObjectByProperty('uuid', temp.uuid);
      console.log(tar);
      console.log(temp.pos);
      tar.position.copy(temp.pos);
      tar.rotation.copy(temp.rot);
      tar.scale.copy(temp.scale);
    }
  }
};
const onKeydown = () => {
  if (outPlay) return;
  const object = control.object;

  objectPositionOnDown = object.position.clone();
  objectRotationOnDown = object.rotation.clone();
  objectScaleOnDown = object.scale.clone();

  controls.enabled = false;
};
const onKeyUp = () => {
  if (outPlay) return;
  const object = control.object;

  if (object !== undefined) {
    editHis.push({
      uuid: object.uuid,
      pos: objectPositionOnDown,
      rot: objectRotationOnDown,
      scale: objectScaleOnDown,
    });
  }

  controls.enabled = true;
};
document.removeEventListener('keydown', backHis);
control.removeEventListener('mouseDown', onKeydown);
control.removeEventListener('mouseUp', onKeyUp);
document.addEventListener('keydown', backHis);

control.addEventListener('mouseDown', onKeydown);

control.addEventListener('mouseUp', onKeyUp);

const ModelMake = () => {
  const inputRef = useRef();
  const [modalVis, SetVis] = useState(false);
  const [curScript, SetCurScript] = useState([]);
  const [playing, SetPlaying] = useState(false);
  const ref = useRef();
  const ImportFileRef = useRef();
  const [object, SetObject] = useState([]);
  const [loading, SetLoading] = useState(false);
  const [animations, SetAni] = useState([]);
  const [code, Setcode] = useState('');
  const [ObjectView, SetObj] = useState(null);
  let selectObject = null;
  let loader = new Loader(scene, object, SetObject, animations, SetAni);
  let raycaster = new THREE.Raycaster();
  let mouse = new THREE.Vector2();
  let onUpPosition;
  let scriptWrapResult = '{start:start,update:update,click:click}';
  const eventInit = () => {
    events = {
      start: [],
      update: [],
      click: {},
    };
    for (var uuid in scripts) {
      let object = scene.getObjectByProperty('uuid', uuid);
      if (object === undefined) {
        message.warn('脚本无绑定对象 ' + uuid, 2);
        continue;
      }

      let cur = scripts[uuid];

      for (let i = 0; i < cur.length; i++) {
        let scriptInstance = cur[i];
        let functions = new Function(
          'scene,message,THREE,mixer,animations',
          scriptInstance.script + '\nreturn ' + scriptWrapResult + ';'
        ).bind(object)(scene, message, THREE, mixer, animations);

        for (let name in functions) {
          if (functions[name] === undefined) continue;

          if (events[name] === undefined) {
            continue;
          }
          if (name != 'click') events[name].push(functions[name].bind(object));
          else {
            if (events['click'][uuid] === undefined) events['click'][uuid] = [];

            events['click'][uuid].push(functions[name].bind(object));
          }
        }
      }
    }
    console.log(events);
    for (let i = 0; i < events.start.length; i++) {
      events.start[i]();
    }
  };
  const addObject = type => {
    let tempObject = null;
    let tempHelper = null;
    if (type === 'pointLight') {
      tempObject = new THREE.PointLight(0xffffff, 5, 1000);
      tempObject.position.set(0, 0, 10);
      tempObject.castShadow = true;
      tempObject.shadow.mapSize.width = 512;
      tempObject.shadow.mapSize.height = 512;
      tempObject.shadow.camera.near = 10;
      tempObject.shadow.camera.far = 200;
      tempObject.shadow.focus = 1;
      const sphereSize = 1;
      tempHelper = new THREE.PointLightHelper(tempObject, sphereSize);
    } else if (type == 'SpotLight') {
      tempObject = new THREE.SpotLight(0xffffff, 100, 100);
      tempObject.position.set(10, 10, 10);
      tempObject.castShadow = true;
      tempObject.shadow.mapSize.width = 512;
      tempObject.shadow.mapSize.height = 512;
      tempObject.shadow.camera.near = 10;
      tempObject.shadow.camera.far = 200;
      tempObject.shadow.focus = 1;
      tempHelper = new THREE.SpotLightHelper(tempObject);
    } else if (type == 'DirectionalLight') {
      tempObject = new THREE.DirectionalLight(0xffffff);
      tempObject.position.set(10, 10, 10);
      tempObject.castShadow = true;
      tempObject.shadow.mapSize.width = 512;
      tempObject.shadow.mapSize.height = 512;
      tempObject.shadow.camera.near = 10;
      tempObject.shadow.camera.far = 200;
      tempObject.shadow.focus = 1;
      tempHelper = new THREE.DirectionalLightHelper(tempObject);
    } else if (type == 'AmbientLight') {
      tempObject = new THREE.AmbientLight(0xffffff);
    }

    if (tempObject === null) return;

    let geometry = new THREE.SphereGeometry(2, 4, 2);
    let material = new THREE.MeshBasicMaterial({
      color: 0xff0000,
      visible: false,
    });

    const picker = new THREE.Mesh(geometry, material);
    picker.tag = 'picker';
    picker.userData.object = tempObject;
    // if (tempHelper != null) tempObject.userData.helper = tempHelper;
    tempObject.tag = 'obj';
    control.attach(tempObject);
    scene.add(tempObject);
    SetObject([...scene.children]);
    control.attach(tempObject);
    if (tempHelper != null) {
      tempHelper.add(picker);
      sceneHelper.add(tempHelper);
    }

    //controls.enabled = false;
  };
  function getMousePosition(dom, x, y) {
    var rect = dom.getBoundingClientRect();
    return [(x - rect.left) / rect.width, (y - rect.top) / rect.height];
  }
  function getIntersects(point) {
    mouse.set(point.x * 2 - 1, -(point.y * 2) + 1);

    raycaster.setFromCamera(mouse, camera);

    const objects = [];

    scene.traverseVisible(function (child) {
      if (child.name == 'environment') {
        return;
      }
      objects.push(child);
    });
    sceneHelper.traverseVisible(child => {
      if (child.tag === 'picker') {
        objects.push(child);
      }
    });
    console.log(objects);
    return raycaster.intersectObjects(objects, false);
  }
  function onMouseDown(event) {
    mulUpload = false;
    //阻止触发dom默认事件
    event.preventDefault();
    //获取鼠标位置

    let array = getMousePosition(renderer.domElement, event.clientX, event.clientY);
    position1 = array;
    onUpPosition = new THREE.Vector2(array[0], array[1]);

    renderer.domElement.addEventListener('mouseup', onMouseUp, false);
  }
  function onMouseUp(event) {
    event.preventDefault();
    let array = getMousePosition(renderer.domElement, event.clientX, event.clientY);
    position2 = array;
    let flag = position1[0] == position2[0] && position1[1] == position2[1];
    if (lightHelperOut != null) lightHelperOut.update();
    // if (selectObject != null && selectObject.userData.helper !== undefined) {
    //   selectObject.userData.helper.update();
    // }
    const intersects = getIntersects(onUpPosition);
    if (outPlay) {
      for (let i = 0; i < intersects.length; i++) {
        let uuid = intersects[i].object.uuid;
        if (events.click[uuid] !== undefined) {
          for (let j = 0; i < events.click[uuid].length; i++) {
            events.click[uuid][j]();
          }
        }
      }
    }
    if (!flag) return;
    if (intersects.length > 0) {
      let object = intersects[0].object;
      console.log(object);
      //判断右边物体选择框是否已经选择
      if (clickSelect) return;

      if (selectObject !== object && !outPlay) {
        //controls.enabled = false;

        if (object.tag == 'picker') {
          console.log(object);
          lightHelperOut = object.parent;
          object = object.userData.object;
        } else {
          lightHelperOut = null;
        }
        SetObj(object);

        if (scripts[object.uuid] === undefined) SetCurScript([]);
        else SetCurScript(scripts[object.uuid]);

        selectObject = object;
        control.attach(object);
      }
    } else {
      SetObj(null);
      SetCurScript([]);
      selectObject = null;
      clickSelect = false;
    }
    if (selectObject == null && flag) {
      //controls.enabled = true;
      control.detach();
    }
  }

  useEffect(() => {
    renderer.setSize(ref.current.offsetWidth, ref.current.offsetHeight);
    // renderer.physicallyCorrectLights = true;
    // renderer.outputEncoding = THREE.sRGBEncoding;
    // renderer.shadowMap.enabled = true;
    // renderer.toneMapping = THREE.ReinhardToneMapping;
    ref.current.appendChild(renderer.domElement);
    stats.dom.style.position = 'absolute';
    stats.dom.style.zIndex = 1000;
    ref.current.appendChild(stats.dom);
    //点击editor

    renderer.domElement.addEventListener('mousedown', onMouseDown, false);
    renderer.autoClear = false;
    SetObject([...scene.children]);
    function animation(time) {
      stats.update();
      controls.update();

      const delta = clock.getDelta();
      mixer.update(delta);

      if (outPlay) {
        for (let i = 0; i < events.update.length; i++)
          events.update[i](delta, clock.getElapsedTime());
      }

      renderer.render(scene, camera);
      if (!outPlay) {
        renderer.render(sceneHelper, camera);
      }
      requestAnimationFrame(animation);
    }

    animation();
  }, []);

  const onSelect = (selectedKeys, info) => {
    clickSelect = true;
    console.log(info);
    let temp = scene.getObjectByProperty('uuid', selectedKeys[0]);
    SetObj(temp);
    if (scripts[temp.uuid] === undefined) SetCurScript([]);
    else SetCurScript(scripts[temp.uuid]);
    selectObject = scene.getObjectByProperty('uuid', selectedKeys[0]);
    if (selectObject == undefined) return;
    control.detach();
    control.attach(selectObject);
    //controls.enabled = false;
  };
  const test = file => {
    return false;
  };
  const props = {
    name: 'file',
    multiple: true,
    headers: {
      authorization: 'authorization-text',
    },
    onChange: test,
    maxCount: 100,
    beforeUpload(fiel, fileList) {
      if (!mulUpload) {
        loader.loadFiles(fileList);
        mulUpload = true;
      } else return false;

      return false;
    },
    showUploadList: false,
  };
  const SaveScene = async () => {
    SetLoading(true);
    console.log(animations);
    let jsonStr = JSON.stringify(scene);
    let scriptStr = JSON.stringify(scripts);
    let ani = [];
    for (let i = 0; i < animations.length; i++) {
      ani.push(animations[i].toJSON());
    }
    let aniStr = JSON.stringify(ani);
    await db.open();

    await db.put(storeName, { id: 1, jsonStr: jsonStr });
    await db.put(storeName, { id: 2, jsonStr: scriptStr });
    await db.put(storeName, { id: 3, jsonStr: aniStr });
    SetLoading(false);
    message.success('保存成功!');
  };
  const LoadScene = async () => {
    SetLoading(true);
    await db.open();
    let res1 = await db.get(storeName, 1);
    let res2 = await db.get(storeName, 2);
    let res3 = await db.get(storeName, 3);
    if (
      res1 === undefined ||
      res1 === null ||
      res2 === undefined ||
      res2 === null ||
      res3 === undefined ||
      res3 === null
    ) {
      message.warning('当前无保存数据', 2);
      SetLoading(false);
      return;
    }
    let json1 = JSON.parse(res1.jsonStr);
    let json2 = JSON.parse(res2.jsonStr);
    let json3 = JSON.parse(res3.jsonStr);
    scripts = json2;
    console.log(json2);
    for (let i = 0; i < json3.length; i++) {
      json3[i] = THREE.AnimationClip.parse(json3[i]);
    }
    console.log(json3);
    SetAni(json3);
    scene = sceneLoader.parse(json1);
    mixer = new THREE.AnimationMixer(scene);
    SetObject(scene.children);
    sceneHelper = new THREE.Scene();
    sceneHelper.add(control);
    SetLoading(false);
    message.success('加载成功!', 2);
  };
  const DownLoadJson = () => {
    let ani = [];
    for (let i = 0; i < animations.length; i++) {
      ani.push(animations[i].toJSON());
    }
    let aniStr = JSON.stringify(ani);
    let json = {
      scene: scene,
      scripts: scripts,
      aniStr: aniStr,
    };
    let blob = new Blob([JSON.stringify(json)], { type: '' });
    let time = moment().format('YYYY-MM-DD HH:mm:ss');
    saveAs(blob, time + '.json');
  };
  const menu1 = (
    <Menu>
      <Menu.Item ref={ImportFileRef}>
        <Upload {...props}>
          <Button>模型导入</Button>
        </Upload>
      </Menu.Item>
      <Menu.Item onClick={DownLoadJson}>下载json文件</Menu.Item>
    </Menu>
  );
  const menu2 = (
    <Menu>
      <Menu.Item
        onClick={() => {
          addObject('pointLight');
        }}
      >
        点光源
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          addObject('SpotLight');
        }}
      >
        聚光灯
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          addObject('DirectionalLight');
        }}
      >
        平面光
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          addObject('AmbientLight');
        }}
      >
        环境光
      </Menu.Item>
    </Menu>
  );
  const menu3 = (
    <Menu>
      <Menu.Item
        onClick={() => {
          addEnv('light');
        }}
      >
        白天地板
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          addEnv('dark');
        }}
      >
        黑夜RGB灯
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          addEnv('darkGround');
        }}
      >
        黑夜地板
      </Menu.Item>
    </Menu>
  );
  const menu4 = (
    <Menu>
      <Menu.Item
        onClick={() => {
          if (ObjectView === null || ObjectView === undefined) {
            message.error('请选择物体', 2);
            return;
          }
          let object = scene.getObjectByProperty('uuid', ObjectView.uuid);
          scene.remove(object);
          if (lightHelperOut !== null) sceneHelper.remove(lightHelperOut);
          SetObject([...scene.children]);
        }}
      >
        删除选中物体
      </Menu.Item>
      <Menu.Item
        onClick={() => {
          scene = new THREE.Scene();
          const geometry = new THREE.BoxGeometry(10, 10, 10);
          const material = new THREE.MeshPhongMaterial({ color: 0x4080ff, dithering: true });

          const mesh = new THREE.Mesh(geometry, material);
          mesh.castShadow = true;
          mesh.tag = 'obj';
          scene.add(mesh);
          scene.background = new THREE.Color(0xffffff);
          sceneHelper = new THREE.Scene();
          sceneHelper.add(control);
          SetObject(scene.children);
          scripts = {};
          SetAni([]);
        }}
      >
        重置场景
      </Menu.Item>
      <Menu.Item itemType="divider"></Menu.Item>
      <Menu.Item onClick={SaveScene}>保存场景</Menu.Item>
      <Menu.Item onClick={LoadScene}>加载场景</Menu.Item>
    </Menu>
  );
  const AnimationClip = props => {
    const [isplaying, SetIsPlaying] = useState(false);
    const AnimationClick = clip => {
      let Action = mixer.clipAction(clip, scene);
      console.log('before', Action);
      if (isplaying) {
        Action.stop();
        SetIsPlaying(!isplaying);
      } else {
        Action.reset();
        Action.play();
        SetIsPlaying(!isplaying);
      }
      console.log('after', Action);
    };
    return (
      <Row style={{ width: '100%', marginBottom: '5px' }}>
        <Col span={8}>{props.index}</Col>
        <Col span={8}>{props.clip.name}</Col>
        <Col span={8}>
          <Button
            style={{ float: 'right' }}
            type="primary"
            size="middle"
            onClick={() => {
              AnimationClick(props.clip);
            }}
          >
            {isplaying ? '暂停' : '播放'}
          </Button>
        </Col>
      </Row>
    );
  };
  const Animation = () => {
    if (animations.length > 0)
      return (
        <>
          {animations.map((clip, index) => {
            return <AnimationClip clip={clip} index={index}></AnimationClip>;
          })}
        </>
      );
    else return <></>;
  };
  const handleOk = () => {
    scripts[ObjectView.uuid][curIndex].script = monacoEditor.getValue();
    SetVis(false);
  };

  const handleCancel = () => {
    SetVis(false);
  };
  const options = {
    selectOnLineNumbers: true,
    roundedSelection: false,
    readOnly: false,
    cursorStyle: 'line',
    automaticLayout: false,
  };
  const ScriptItem = props => {
    return (
      <Row style={{ marginBottom: '5px' }}>
        <Col span={8}>{props.val.name}</Col>
        <Col span={8}></Col>
        <Col span={8}>
          <Button
            onClick={() => {
              Setcode(props.val.script);
              curIndex = props.index;
              SetVis(true);
            }}
          >
            编辑
          </Button>
        </Col>
      </Row>
    );
  };
  const ScriptPanel = props => {
    if (props.cur === undefined && ObjectView === null) return <></>;

    return (
      <>
        {props.cur.map((val, index) => {
          return <ScriptItem val={val} index={index} />;
        })}
        {ObjectView !== null ? (
          <Row>
            <Col span={16}>
              <Input ref={inputRef} placeholder="请输入新脚本名" />
            </Col>
            <Col span={8}>
              <Button
                onClick={() => {
                  if (scripts[ObjectView.uuid] === undefined) scripts[ObjectView.uuid] = [];
                  scripts[ObjectView.uuid].push({
                    key: scripts[ObjectView.uuid].length,
                    name: inputRef.current.input.defaultValue,
                    script:
                      'function start()\n' +
                      '{\n' +
                      '\n' +
                      '}\n' +
                      '\n' +
                      'function update(time,elapsedTime)\n' +
                      '{\n' +
                      '\n' +
                      '}\n' +
                      '\n' +
                      'function click()\n' +
                      '{\n' +
                      '\n' +
                      '}',
                  });
                  SetCurScript([...scripts[ObjectView.uuid]]);
                }}
              >
                新增
              </Button>
            </Col>
          </Row>
        ) : (
          <></>
        )}
      </>
    );
  };
  const addEnv = async type => {
    if (type == 'light') {
      const light = new THREE.DirectionalLight(0xaabbff, 0.3);
      light.position.x = 300;
      light.position.y = 250;
      light.position.z = -500;

      scene.add(light);

      const vertexShader = document.getElementById('vertexShader').textContent;
      const fragmentShader = document.getElementById('fragmentShader').textContent;
      const uniforms = {
        topColor: { value: new THREE.Color(0x0077ff) },
        bottomColor: { value: new THREE.Color(0xffffff) },
        offset: { value: 400 },
        exponent: { value: 0.6 },
      };
      uniforms.topColor.value.copy(light.color);

      const skyGeo = new THREE.SphereGeometry(4000, 32, 15);
      const skyMat = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        side: THREE.BackSide,
      });

      const sky = new THREE.Mesh(skyGeo, skyMat);
      sky.name = 'environment';
      scene.add(sky);

      const floorGeometry = new THREE.PlaneGeometry(500, 500);
      const floorMesh = new THREE.Mesh(floorGeometry, floorMat);

      floorMesh.receiveShadow = true;
      floorMesh.rotation.x = -Math.PI / 2.0;
      floorMesh.name = 'environment';
      floorMesh.receiveShadow = true;
      scene.add(floorMesh);
      SetObject([...object, sky, floorMesh, light]);
    } else if (type == 'dark') {
      scene.background = new THREE.Color(0x000000);
      RectAreaLightUniformsLib.init();

      const rectLight1 = new THREE.RectAreaLight(0xff0000, 5, 4, 10);
      rectLight1.position.set(-5, 5, 5);
      rectLight1.name = 'environment';
      scene.add(rectLight1);

      const rectLight2 = new THREE.RectAreaLight(0x00ff00, 5, 4, 10);
      rectLight2.position.set(0, 5, 5);
      rectLight2.name = 'environment';
      scene.add(rectLight2);

      const rectLight3 = new THREE.RectAreaLight(0x0000ff, 5, 4, 10);
      rectLight3.position.set(5, 5, 5);
      rectLight3.name = 'environment';
      scene.add(rectLight3);

      scene.add(new RectAreaLightHelper(rectLight1));
      scene.add(new RectAreaLightHelper(rectLight2));
      scene.add(new RectAreaLightHelper(rectLight3));

      const geoFloor = new THREE.BoxGeometry(2000, 0.1, 2000);
      const matStdFloor = new THREE.MeshStandardMaterial({
        color: 0x808080,
        roughness: 0.1,
        metalness: 0,
      });
      const mshStdFloor = new THREE.Mesh(geoFloor, matStdFloor);
      mshStdFloor.receiveShadow = true;
      mshStdFloor.name = 'environment';
      scene.add(mshStdFloor);
      SetObject([...scene.children]);
      //SetObject([...object, rectLight1, rectLight2, rectLight3,mshStdFloor]);
    } else if (type == 'darkGround') {
      const floorGeometry = new THREE.PlaneGeometry(500, 500);
      const floorMesh = new THREE.Mesh(floorGeometry, floorMat);
      scene.background = new THREE.Color(0x000000);
      floorMesh.receiveShadow = true;
      floorMesh.rotation.x = -Math.PI / 2.0;
      floorMesh.name = 'environment';
      floorMesh.receiveShadow = true;
      scene.add(floorMesh);

      SetObject([...object, floorMesh]);
    }
  };
  const StartScene = async e => {
    e.preventDefault();
    SetLoading(true);
    if (!playing) {
      control.enabled = false;
      //let jsonStr = JSON.stringify(scene);

      //await db.put(storeName, { id: 4, jsonStr: jsonStr });
      // cloneScene = scene.clone();
      eventInit();
      clock.start();
    } else {
      //let res = await db.get(storeName, 4);
      //let json = JSON.parse(res.jsonStr);
      //scene = sceneLoader.parse(cloneScene);
      // scene.copy(cloneScene);
      if (window.ws !== undefined) {
        delete window.ws;
      }
      mixer = new THREE.AnimationMixer(scene);
      control.enabled = true;
    }

    SetPlaying(!playing);
    outPlay = !outPlay;
    SetLoading(false);
  };
  return (
    <>
      <Layout>
        <Spin spinning={loading}>
          <Content style={{ padding: '5px 0px', backgroundColor: '#FAFAFA', height: '82vh' }}>
            <Row style={{ height: '5%', backgroundColor: '#FAFAFA' }}>
              <Col style={{ height: '100%' }} span={2}>
                <Dropdown style={{ float: 'left' }} overlay={menu1} trigger={['click']}>
                  <a onClick={e => e.preventDefault()}>
                    <Space>文件</Space>
                  </a>
                </Dropdown>
              </Col>
              <Col style={{ height: '100%' }} span={2}>
                <Dropdown overlay={menu2} trigger={['click']}>
                  <a onClick={e => e.preventDefault()}>
                    <Space>添加</Space>
                  </a>
                </Dropdown>
              </Col>
              <Col style={{ height: '100%' }} span={2}>
                <a onClick={StartScene}>
                  <Space>{playing ? '暂停' : '播放'}</Space>
                </a>
              </Col>
              <Col style={{ height: '100%' }} span={2}>
                <Dropdown overlay={menu3} trigger={['click']}>
                  <a onClick={e => e.preventDefault()}>
                    <Space>环境</Space>
                  </a>
                </Dropdown>
              </Col>
              <Col style={{ height: '100%' }} span={2}>
                <Dropdown overlay={menu4} trigger={['click']}>
                  <a onClick={e => e.preventDefault()}>
                    <Space>编辑</Space>
                  </a>
                </Dropdown>
              </Col>
            </Row>
            <Row style={{ height: '95%' }}>
              <Col style={{ height: '100%' }} span={20}>
                <div style={{ height: '100%', width: '100%' }} ref={ref}>
                  <Segmented
                    defaultValue={'translate'}
                    style={{
                      position: 'absolute',
                      left: '2px',
                      bottom: '0px',
                      backgroundColor: '#F3F3F3',
                    }}
                    onChange={val => {
                      control.setMode(val);
                    }}
                    options={[
                      {
                        label: (
                          <>
                            <img
                              style={{ color: 'white', height: '20px', width: '20px' }}
                              src={translate}
                            />
                          </>
                        ),
                        value: 'translate',
                      },
                      {
                        label: (
                          <>
                            <img
                              style={{ color: 'white', height: '20px', width: '20px' }}
                              src={rotate}
                            />
                          </>
                        ),
                        value: 'rotate',
                      },
                      {
                        label: (
                          <>
                            <img
                              style={{ color: 'white', height: '20px', width: '20px' }}
                              src={scale}
                            />
                          </>
                        ),
                        value: 'scale',
                      },
                    ]}
                  />
                </div>
              </Col>
              <Col style={{ height: '100%', backgroundColor: '#FAFAFA' }} span={4}>
                <Row style={{ height: '300px', padding: '20px', width: '100%' }}>
                  <Tree
                    virtual
                    fieldNames={{
                      title: 'type',
                      key: 'uuid',
                    }}
                    rootStyle={{ width: '100%', height: '100%', overflowY: 'scroll' }}
                    showLine={true}
                    defaultExpandedKeys={['0-0-0']}
                    onSelect={onSelect}
                    treeData={object}
                  />
                </Row>
                <Row style={{ padding: '20px', width: '100%', paddingTop: '0px' }}>
                  <Tabs
                    style={{
                      backgroundColor: 'white',
                      width: '100%',
                      height: '400px',
                      overflowY: 'auto',
                    }}
                    defaultActiveKey="1"
                  >
                    <TabPane
                      tab={
                        <span>
                          <CodeSandboxOutlined />
                          物体
                        </span>
                      }
                      key="1"
                    >
                      {ObjectView === null || ObjectView === undefined ? (
                        <></>
                      ) : (
                        <>
                          <Descriptions style={{ paddingLeft: '5px' }}>
                            <Descriptions.Item
                              label={<h3 style={{ fontWeight: 'bold' }}>物体类型</h3>}
                              span={3}
                            >
                              {ObjectView.type}
                            </Descriptions.Item>
                            <Descriptions.Item
                              span={3}
                              label={<h3 style={{ fontWeight: 'bold' }}>UUID</h3>}
                            >
                              {ObjectView.uuid}
                            </Descriptions.Item>
                            <Descriptions.Item
                              span={3}
                              label={<h3 style={{ fontWeight: 'bold' }}>物体名称</h3>}
                            >
                              {ObjectView.name}
                            </Descriptions.Item>
                            <Descriptions.Item
                              span={3}
                              label={<h3 style={{ fontWeight: 'bold' }}>位置</h3>}
                            >
                              {ObjectView.position.x.toFixed(2)} {ObjectView.position.y.toFixed(2)}{' '}
                              {ObjectView.position.z.toFixed(2)}
                            </Descriptions.Item>
                            <Descriptions.Item
                              label={<h3 style={{ fontWeight: 'bold' }}>角度</h3>}
                              span={3}
                            >
                              {ObjectView.rotation.x.toFixed(2)} {ObjectView.rotation.y.toFixed(2)}{' '}
                              {ObjectView.rotation.z.toFixed(2)}
                            </Descriptions.Item>
                            <Descriptions.Item
                              label={<h3 style={{ fontWeight: 'bold' }}>规模</h3>}
                              span={3}
                            >
                              {ObjectView.scale.x.toFixed(2)} {ObjectView.scale.y.toFixed(2)}{' '}
                              {ObjectView.scale.z.toFixed(2)}
                            </Descriptions.Item>
                            {ObjectView.intensity !== undefined ? (
                              <Descriptions.Item
                                label={<h3 style={{ fontWeight: 'bold' }}>光源强度</h3>}
                                span={3}
                              >
                                <InputNumber
                                  value={ObjectView.intensity}
                                  min={0}
                                  max={1000}
                                  onChange={val => {
                                    if (val === null) return;
                                    let obj = scene.getObjectByProperty('uuid', ObjectView.uuid);
                                    obj.intensity = val;
                                    ObjectView = {
                                      ...ObjectView,
                                      intensity: val,
                                    };
                                  }}
                                ></InputNumber>
                              </Descriptions.Item>
                            ) : (
                              <></>
                            )}
                            {ObjectView.distance !== undefined ? (
                              <Descriptions.Item
                                label={<h3 style={{ fontWeight: 'bold' }}>光源距离</h3>}
                                span={3}
                              >
                                <InputNumber
                                  value={ObjectView.distance}
                                  min={0}
                                  max={1000}
                                  onChange={val => {
                                    if (val === null) return;
                                    let obj = scene.getObjectByProperty('uuid', ObjectView.uuid);
                                    obj.distance = val;
                                    ObjectView = {
                                      ...ObjectView,
                                      distance: val,
                                    };
                                  }}
                                ></InputNumber>
                              </Descriptions.Item>
                            ) : (
                              <></>
                            )}
                          </Descriptions>
                        </>
                      )}
                    </TabPane>
                    <TabPane
                      tab={
                        <span>
                          <PlaySquareOutlined />
                          动画
                        </span>
                      }
                      key="2"
                      style={{ padding: '5px', width: '100%' }}
                    >
                      {Animation()}
                    </TabPane>
                    <TabPane
                      tab={
                        <span>
                          <CopyOutlined />
                          脚本
                        </span>
                      }
                      key="3"
                    >
                      <ScriptPanel cur={curScript} />
                    </TabPane>
                  </Tabs>
                </Row>
              </Col>
            </Row>
          </Content>
        </Spin>
      </Layout>
      <Modal width={1300} visible={modalVis} onOk={handleOk} onCancel={handleCancel}>
        <Row>
          <Col span={16}>
            <MonacoEditor
              width="100%"
              height="600"
              language="javascript"
              theme="vs-light"
              value={code}
              editorDidMount={(editor, monaco) => {
                monacoEditor = editor;
              }}
              options={options}
            />
          </Col>
          <Col style={{ padding: '10px' }} span={8}>
            <Tabs
              style={{
                backgroundColor: 'white',
                width: '100%',
                height: '100%',
                overflowY: 'auto',
              }}
              defaultActiveKey="1"
            >
              <TabPane style={{ fontSize: '16px' }} tab={<span>脚本申明</span>} key="1">
                <Row style={{ width: '100%' }}>
                  用户输入会被作为函数执行，this指向当前脚本绑定的object。其中start、update、click会被当做函数返回，请勿输入return语句。
                </Row>
                <Row style={{ width: '100%' }}>
                  提供给用户操作的对象有scene、message、THREE、mixer、animations
                </Row>
                <Row style={{ width: '100%' }}>scene：当前场景对象</Row>
                <Row style={{ width: '100%' }}>message：antd的消息对象，可弹窗</Row>
                <Row style={{ width: '100%' }}>THREE：three对象</Row>
                <Row style={{ width: '100%' }}>mixer：当前场景动画混合器</Row>
                <Row style={{ width: '100%' }}>animation：数组，存储当前场景所有动画Clip</Row>

                <Row style={{ width: '100%', marginTop: '20px' }}>函数申明</Row>
                <Row style={{ width: '100%', marginTop: '20px' }}>
                  start函数将在场景开始后执行一次
                </Row>
                <Row style={{ width: '100%', marginTop: '20px' }}>
                  update函数将在每一帧执行一次,参数time为每帧间间隔时间，单位为s
                </Row>
                <Row style={{ width: '100%', marginTop: '20px' }}>
                  click函数将在物体被点击后执行一次，只有脚本绑定物体为mesh网格时生效！
                </Row>
              </TabPane>
              <TabPane tab={<span>相关文档</span>} key="2">
                <Row>
                  <a target={'_blank'} href="https://ant.design/components/message-cn/">
                    message文档
                  </a>
                </Row>
                <Row>
                  <a target={'_blank'} href="http://www.webgl3d.cn/threejs/docs/">
                    three.js文档
                  </a>
                </Row>
              </TabPane>
            </Tabs>
          </Col>
        </Row>
      </Modal>
    </>
  );
};

export default () => {
  const { authority } = UserAuth('InBatch');
  return <>{authority ? <ModelMake /> : <NotAuth />}</>;
};
